
#include "Edglet.h"

// [*] CEdglet

const double CEdglet::ExistThreshold_BlackStrength = 0.01;
const double CEdglet::LengthRatio_DrawingEdge = 0.8;

CEdglet::CEdglet(int EdgletLabel)
{
	this->label = EdgletLabel;
}

void CEdglet::myInit(int EdgletLabel)
{
	this->label = EdgletLabel;
}

void CEdglet::Clear()
{
	label = -1;
}

bool CEdglet::fDoesExist() const
{
	return (label>=0 && label<Amount_Edglet);
}

bool CEdglet::FromBinPair(int b1, int b2)
{
	int t;
	if (b1 > b2) { t = b1; b1 = b2; b2 = t; }

	label = -1;
	if (b1<0 || b1==b2 || b2>=Amount_OriBin) return false;

	label = (Amount_OriBin + Amount_OriBin - 1 - b1) * b1 / 2 + b2 - b1 - 1;
	return true;
}

bool CEdglet::ToBinPair(int& b1, int& b2) const
{
	b1 = b2 = 0;
	if (label<0 || label>=Amount_Edglet) return false;

	int tt = label;
	b1 = 0; b2 = Amount_OriBin - 1;
	for ( ; ; )
	{
		if (tt < b2)
		{
			b2 = b1 + 1 + tt;
			break;
		}
		tt -= b2;
		++b1; --b2;
	}
	return true;
}

double CEdglet::FromImage(const int* qBaseBW, int W, int H, const CRectBox<int>& iBox)
{
	int xa, ya, xb, yb;
	int ix, iy, o1, o2;
	double dx, dy, cx, cy;
	double ta, tv;

	if (W<1 || H<1)
	{
		label = -1;
		return 0.0;
	}

	xa = iBox.x; ya = iBox.y;
	xb = iBox.x + iBox.w - 1;
	yb = iBox.y + iBox.h - 1;

	xa = (xa<0 ? xa : (xa>=W ? W-1 : xa));
	xb = (xb<0 ? xb : (xb>=W ? W-1 : xb));
	ya = (ya<0 ? ya : (ya>=H ? H-1 : ya));
	yb = (yb<0 ? yb : (yb>=H ? H-1 : yb));

	cx = (xa + xb + 1) * 0.5;
	cy = (ya + yb + 1) * 0.5;

	CHistogramConfig HistConfig;
	ta = PI / Amount_OriBin;
	HistConfig.myInit(Amount_OriBin, true, -ta, PI+PI-ta);
	CSimpleTypeArray<double> OriHist;
	OriHist.Resize(Amount_OriBin); OriHist.Fill(0.0);
	double* ph = OriHist.pElement;

	const int* qi;
	double ret = 0.0;
	for ( iy = ya; iy <= yb; ++iy )
	{
		dy = iy + 0.5 - cy;
		qi = qBaseBW + xa + iy * W;
		for ( ix = xa; ix <= xb; ++ix )
		{
			dx = ix + 0.5 - cx;
			if (*(qi++) > 127) continue;
			//if (abs(dx)<EPS && abs(dy)<EPS) continue;

			ret += 1.0;
			ta = atan2(dy, dx);
			tv = HistConfig.SelectBin_Bounding(o1, o2, ta);
			ph[o1] += 1.0 - tv;
			ph[o2] += tv;
		}
	}

	//if (ret > EPS)
	//	ret = ret;

	//ix = ; if (ix%2==0) --ix;
	ret /= (1+xb-xa)*(1+yb-ya);

	if (ret > ExistThreshold_BlackStrength)
	{
		if (ph[0] > ph[1])
		{ iy = 0; ix = 1; }
		else
		{ iy = 1; ix = 0; }
		for ( o1 = 2; o1 < Amount_OriBin; ++o1 )
		{
			if (ph[ix] > ph[o1]) continue;
			if (ph[iy] > ph[o1])
				ix = o1;
			else
			{
				ix = iy;
				iy = o1;
			}
		}
		o1 = o1;
		FromBinPair(ix, iy);
	}
	else
	{
		this->Clear();
	}

	return ret;
}

void CEdglet::ToImage(int* pBaseBW, int W, int H, const CRectBox<int>& iBox) const
{
	int xa, ya, xb, yb;
	int ix, iy, o1, o2;

	if (W<1 || H<1) return;

	xa = iBox.x; ya = iBox.y;
	xb = iBox.x + iBox.w - 1;
	yb = iBox.y + iBox.h - 1;

	xa = (xa<0 ? xa : (xa>=W ? W-1 : xa));
	xb = (xb<0 ? xb : (xb>=W ? W-1 : xb));
	ya = (ya<0 ? ya : (ya>=H ? H-1 : ya));
	yb = (yb<0 ? yb : (yb>=H ? H-1 : yb));

	int* pd;
	for ( iy = ya; iy <= yb; ++iy )
	{
		pd = pBaseBW + xa + iy * W;
		for ( ix = xa; ix <= xb; ++ix ) *(pd++) = 255;
	}

	if (!ToBinPair(o1, o2)) return;

	DrawEdgeSegmentToImage(pBaseBW, W, H, xa, ya, xb, yb, o1, 1.0);
	DrawEdgeSegmentToImage(pBaseBW, W, H, xa, ya, xb, yb, o2, 1.0);
}


void ideal_observer::CEdglet::DrawEdgeSegmentToImage(
	int *pBaseBW, int w, int h,
	int xa, int ya, int xb, int yb,
	int EdgeOriBin, double Probability)
{
	int _color = (int)(256 * (1.0 - Probability));
	_color = (_color<0 ? 0 : (_color>255 ? 255 : _color));

	int cw = (xb - xa + 1);
	int ch = (yb - ya + 1);
	double rr = sqrt(1.0 * cw * ch) * 0.5 * LengthRatio_DrawingEdge;

	CImg<int> imgDraw;
	imgDraw.assign(pBaseBW, w, h, 1, 1, true);

	double tx, ty, cx, cy;
	cx = (xa + xb + 1) * 0.5;
	cy = (ya + yb + 1) * 0.5;

	double AA = 1.0;
	int BB = 0;
	double ta = (PI+PI) / Amount_OriBin * EdgeOriBin;

	for ( int iii = -BB; iii <= +BB; ++iii )
	{
		double dx = cos(ta);
		double dy = sin(ta);
		tx = cx + rr * dx;
		ty = cy + rr * dy;
		imgDraw.draw_line(
			//CMyMath::TranslateNumber_Floor(cx - iii * AA * dy, 1e-2),
			//CMyMath::TranslateNumber_Floor(cy + iii * AA * dx, 1e-2),
			//CMyMath::TranslateNumber_Floor(tx - iii * AA * dy, 1e-2),
			//CMyMath::TranslateNumber_Floor(ty + iii * AA * dx, 1e-2),
			CMyMath::TranslateNumber_Round(cx - iii * AA * dy, (int)0),
			CMyMath::TranslateNumber_Round(cy + iii * AA * dx, (int)0),
			CMyMath::TranslateNumber_Round(tx - iii * AA * dy, (int)0),
			CMyMath::TranslateNumber_Round(ty + iii * AA * dx, (int)0),
			CExternalTools::GetIntArrayRGB(_color, _color, _color));
	}
}

void ideal_observer::CEdglet::DrawCellDistributionToImage( int *pBaseBW, int W, int H, const CRectBox<int>& iBox, const double* pBase_P )
{
	int xa, ya, xb, yb;
	int ix, iy, i, o1, o2;
	CEdglet te;
	double tt = 0.0;
	int* pd;

	if (W<1 || H<1) return;

	xa = iBox.x; ya = iBox.y;
	xb = iBox.x + iBox.w - 1;
	yb = iBox.y + iBox.h - 1;

	xa = (xa<0 ? xa : (xa>=W ? W-1 : xa));
	xb = (xb<0 ? xb : (xb>=W ? W-1 : xb));
	ya = (ya<0 ? ya : (ya>=H ? H-1 : ya));
	yb = (yb<0 ? yb : (yb>=H ? H-1 : yb));

#if 1
	int GrayLowerBound = 32;
	double HE_Threshold = CMyMath::my_log(Amount_Edglet); // 3.00; // CMyMath::my_log(Amount_Edglet);
	double he = 0.0;
	int i_max_tt = -1;
	double max_tt = 0.0;
	for ( i = 0; i < Amount_Edglet; ++i )
	{
		tt = pBase_P[i];
		if (tt > MINIMUM_DOUBLE_EPS_C)
			he -= tt * CMyMath::my_log(tt);
		if (i_max_tt<0 || max_tt<tt)
		{
			i_max_tt = i;
			max_tt = tt;
		}
	}
	te.myInit(i_max_tt); te.ToBinPair(o1, o2);
	i_max_tt = (int)((255-GrayLowerBound) * he / HE_Threshold);
	i_max_tt = 255 - (i_max_tt<0 ? 0 : (i_max_tt>(255-GrayLowerBound) ? (255-GrayLowerBound) : i_max_tt));
	for ( iy = ya; iy <= yb; ++iy )
	{
		pd = pBaseBW + xa + iy * W;
		for ( ix = xa; ix <= xb; ++ix ) *(pd++) = i_max_tt;
	}
	DrawEdgeSegmentToImage(pBaseBW, W, H, xa, ya, xb, yb, o1, 1.0);
	DrawEdgeSegmentToImage(pBaseBW, W, H, xa, ya, xb, yb, o2, 1.0);
#else
	for ( iy = ya; iy <= yb; ++iy )
	{
		pd = pBaseBW + xa + iy * W;
		for ( ix = xa; ix <= xb; ++ix ) *(pd++) =  255;
	}
	CSimpleTypeArray<double> ep;
	ep.Resize(Amount_OriBin); ep.Fill(0.0);
	double* pep = ep.pElement;
	for ( i = 0; i < Amount_Edglet; ++i )
	{
		te.myInit(i);
		te.ToBinPair(o1, o2);
		pep[o1] += pBase_P[i];
		pep[o2] += pBase_P[i];
	}
	//tt = EPS; for ( i = 0; i < Amount_OriBin; ++i ) if (tt < pep[i]) tt = pep[i];
	//tt = EPS; for ( i = 0; i < Amount_OriBin; ++i ) tt += pep[i];
	//for ( i = 0; i < Amount_OriBin; ++i ) pep[i] /= tt;
	for ( i = 0; i < Amount_OriBin; ++i )
	{
		if (pep[i] < EPS) continue;
		DrawEdgeSegmentToImage(pBaseBW, W, H, xa, ya, xb, yb, i, pep[i]);
	}
#endif
}

